#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <vector>

using namespace std;

class ChildP
{
public:
    ChildP(int wfd, pid_t pid, const string &name)
        : _wfd(wfd), _pid(pid), _name(name)
    {
    }

    int getwfd() { return _wfd; }
    pid_t getpid() { return _pid; }
    string getname() { return _name; }

private:
    int _wfd;     // 父进程的写端
    pid_t _pid;   // 子进程的pid
    string _name; // 子进程的名字
};

void ReadTask(int rfd, int pid)
{
    while (true)
    {
        char buffer[200];
        ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);
        if (n > 0)
        {
            buffer[n] = '\0';
            printf("子进程: %d 正在执行:> %s\n", pid, buffer);
        }
        else if (n == 0)
        {
            printf("子进程: %d 退出...\n", pid);
            break;
        }
        else
        {
            printf("read fail, errno is %d, errstr is %s\n", errno, strerror(errno));
            return;
        }

        sleep(1);
    }
}

// 创建 sp_num 个子进程
void CreateSubProcess(int sp_num, vector<ChildP> &ChildPs)
{
    vector<int> f_wfd;
    for (int i = 0; i < sp_num; ++i)
    {
        // 创建管道
        int pipefd[2] = {0};
        pipe(pipefd);

        pid_t id = fork();
        if (id < 0)
        {
            // 创建子进程失败
            printf("fork fail, errno is %d, errstr is %s\n", errno, strerror(errno));
        }
        else if (id == 0)
        {
            // 关闭父进程指向其他管道的写端
            cout << "close ";
            for(int e : f_wfd)
            {
                close(e);
                cout << e << " ";
            }
            cout << endl;

            // 子进程读取任务
            // 关闭写端
            close(pipefd[1]);

            // 读
            ReadTask(pipefd[0], getpid());

            exit(0);
        }
        //sleep(2);
        // 父进程派发任务，关闭读端
        close(pipefd[0]);
        // 父进程需要记录每个父进程的写端wfd。为了方便查看，顺便记录名字和pid
        string name = "process " + to_string(i);
        ChildPs.push_back(ChildP(pipefd[1], id, name));
        f_wfd.push_back(pipefd[1]);
    }
}

void WriteTask(ChildP &cp)
{
    char buffer[1024];
    static int i = 1;
    snprintf(buffer, sizeof(buffer) - 1, "Task %d", i);
    ++i;

    write(cp.getwfd(), buffer, strlen(buffer));

    // 打印确认信息
    cout << "Aleady Send a Task to " << cp.getname() << " ,pid is " << cp.getpid() << endl;
}

void SendTask(vector<ChildP> &ChildPs, int sp_num, int TaskNum)
{
    int PNode = 0;
    while (TaskNum--)
    {
        WriteTask(ChildPs[PNode]);
        sleep(1);
        PNode = (PNode + 1) % sp_num;
    }
}

int main()
{
    int sp_num = 5;
    vector<ChildP> ChildPs;

    CreateSubProcess(sp_num, ChildPs);

    int TaskNum = 7;

    SendTask(ChildPs, sp_num, TaskNum);

    for(auto& cp : ChildPs)
    {
        // 关闭写端
        close(cp.getwfd());
        cout << "子进程: " << cp.getname() << " pid is " << cp.getpid() << " close" << endl;
    }

    for(auto& cp : ChildPs)
    {
        // 阻塞式等待
        waitpid(cp.getpid(), nullptr, 0);
        cout << "wait successfully: " << cp.getname() << " ,pid is " << cp.getpid() << endl;
    }

    return 0;
}